//
//  UIViewController+SFNavigationBarManager.m
//  Pods-SFNavigationBarManager_Example
//
//  Created by shen on 2021/11/17.
//

#import "UIViewController+SFNavigationBarManager.h"
#import <objc/runtime.h>
#import "SFSwizzle.h"
#import "UINavigationController+SFNavigationBarManager.h"
#import "UIScrollView+SFNavigationBarManager.h"

@implementation UIViewController (SFNavigationBarManager)

#pragma mark - Runtime

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        SFSwizzleMethod([self class], @selector(viewWillLayoutSubviews),
                        [self class], @selector(sf_viewWillLayoutSubviews));

        SFSwizzleMethod([self class], @selector(viewWillAppear:),
                        [self class], @selector(sf_viewWillAppear:));

        SFSwizzleMethod([self class], @selector(viewDidAppear:),
                        [self class], @selector(sf_viewDidAppear:));
    });
}

- (void)sf_viewWillAppear:(BOOL)animated {
    [self sf_viewWillAppear:animated];
    [self.navigationController setNavigationBarHidden:self.sf_navBarHidden animated:animated];

    id<UIViewControllerTransitionCoordinator> tc = self.transitionCoordinator;
    UIViewController *toViewController = [tc viewControllerForKey:UITransitionContextToViewControllerKey];

    if ([self isEqual:self.navigationController.viewControllers.lastObject] && [toViewController isEqual:self]  && tc.presentationStyle == UIModalPresentationNone) {
        [self sf_adjustScrollViewContentInsetAdjustmentBehavior];
        dispatch_async(dispatch_get_main_queue(), ^{
            if (self.navigationController.navigationBarHidden) {
                [self sf_restoreScrollViewContentInsetAdjustmentBehaviorIfNeeded];
            }
        });
    }
}

- (void)sf_viewDidAppear:(BOOL)animated {
    [self sf_restoreScrollViewContentInsetAdjustmentBehaviorIfNeeded];
    UIViewController *transitionViewController = self.navigationController.sf_transitionContextToViewController;
    if (self.sf_transitionNavigationBar) {
        if (@available(iOS 15, *)) {
            self.navigationController.navigationBar.standardAppearance = self.sf_transitionNavigationBar.standardAppearance;
            self.navigationController.navigationBar.scrollEdgeAppearance = self.sf_transitionNavigationBar.scrollEdgeAppearance;
        } else {
            self.navigationController.navigationBar.barTintColor = self.sf_transitionNavigationBar.barTintColor;
            [self.navigationController.navigationBar setBackgroundImage:[self.sf_transitionNavigationBar backgroundImageForBarMetrics:UIBarMetricsDefault] forBarMetrics:UIBarMetricsDefault];
            [self.navigationController.navigationBar setShadowImage:self.sf_transitionNavigationBar.shadowImage];
        }
        if (!transitionViewController || [transitionViewController isEqual:self]) {
            [self.sf_transitionNavigationBar removeFromSuperview];
            self.sf_transitionNavigationBar = nil;
        }
    }
    if ([transitionViewController isEqual:self]) {
        self.navigationController.sf_transitionContextToViewController = nil;
    }
    self.navigationController.sf_backgroundViewHidden = NO;
    [self sf_viewDidAppear:animated];
}

- (void)sf_viewWillLayoutSubviews {
    id<UIViewControllerTransitionCoordinator> tc = self.transitionCoordinator;
    UIViewController *fromViewController = [tc viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toViewController = [tc viewControllerForKey:UITransitionContextToViewControllerKey];

    if ([self isEqual:self.navigationController.viewControllers.lastObject] && [toViewController isEqual:self] && tc.presentationStyle == UIModalPresentationNone) {
        if (self.navigationController.navigationBar.translucent) {
            [tc containerView].backgroundColor = [self.navigationController sf_containerViewBackgroundColor];
        }
        fromViewController.view.clipsToBounds = NO;
        toViewController.view.clipsToBounds = NO;
        if (!self.sf_transitionNavigationBar) {
            [self sf_addTransitionNavigationBarIfNeeded];
            self.navigationController.sf_backgroundViewHidden = YES;
        }
        [self sf_resizeTransitionNavigationBarFrame];
    }
    if (self.sf_transitionNavigationBar) {
        [self.view bringSubviewToFront:self.sf_transitionNavigationBar];
    }
    [self sf_viewWillLayoutSubviews];
}

- (void)sf_resizeTransitionNavigationBarFrame {
    if (!self.view.window) {
        return;
    }
    UIView *backgroundView = [self.navigationController.navigationBar valueForKey:@"_backgroundView"];
    CGRect rect = [backgroundView.superview convertRect:backgroundView.frame toView:self.view];
    self.sf_transitionNavigationBar.frame = rect;
}

- (void)sf_addTransitionNavigationBarIfNeeded {
    if (!self.isViewLoaded || !self.view.window) {
        return;
    }
    if (!self.navigationController.navigationBar) {
        return;
    }
    [self sf_adjustScrollViewContentOffsetIfNeeded];
    UINavigationBar *bar = [[UINavigationBar alloc] init];
    bar.sf_isFakeBar = YES;
    if (@available(iOS 14, *)) {
        bar.items = @[[UINavigationItem new]]; // fix Apple's bug in iOS 14
    }
    bar.barStyle = self.navigationController.navigationBar.barStyle;
    if (bar.translucent != self.navigationController.navigationBar.translucent) {
        bar.translucent = self.navigationController.navigationBar.translucent;
    }
    if (@available(iOS 15, *)) {
        bar.standardAppearance = self.navigationController.navigationBar.standardAppearance;
        bar.scrollEdgeAppearance = self.navigationController.navigationBar.scrollEdgeAppearance;
    } else {
        bar.barTintColor = self.navigationController.navigationBar.barTintColor;
        [bar setBackgroundImage:[self.navigationController.navigationBar backgroundImageForBarMetrics:UIBarMetricsDefault] forBarMetrics:UIBarMetricsDefault];
        bar.shadowImage = self.navigationController.navigationBar.shadowImage;
    }
    [self.sf_transitionNavigationBar removeFromSuperview];
    self.sf_transitionNavigationBar = bar;
    [self sf_resizeTransitionNavigationBarFrame];
    if (!self.navigationController.navigationBarHidden && !self.navigationController.navigationBar.hidden) {
        [self.view addSubview:self.sf_transitionNavigationBar];
    }
}

- (void)sf_adjustScrollViewContentOffsetIfNeeded {
    UIScrollView *scrollView = self.sf_visibleScrollView;
    if (scrollView) {
        UIEdgeInsets contentInset;
#ifdef __IPHONE_11_0
        if (@available(iOS 11.0, *)) {
            contentInset = scrollView.adjustedContentInset;
        } else {
            contentInset = scrollView.contentInset;
        }
#else
        contentInset = scrollView.contentInset;
#endif
        const CGFloat topContentOffsetY = -contentInset.top;
        const CGFloat bottomContentOffsetY = scrollView.contentSize.height - (CGRectGetHeight(scrollView.bounds) - contentInset.bottom);

        CGPoint adjustedContentOffset = scrollView.contentOffset;
        if (adjustedContentOffset.y > bottomContentOffsetY) {
            adjustedContentOffset.y = bottomContentOffsetY;
        }
        if (adjustedContentOffset.y < topContentOffsetY) {
            adjustedContentOffset.y = topContentOffsetY;
        }
        [scrollView setContentOffset:adjustedContentOffset animated:NO];
    }
}

- (void)sf_adjustScrollViewContentInsetAdjustmentBehavior {
#ifdef __IPHONE_11_0
    if (self.navigationController.navigationBar.translucent) {
        return;
    }
    if (@available(iOS 11.0, *)) {
        UIScrollView *scrollView = self.sf_visibleScrollView;
        if (scrollView) {
            UIScrollViewContentInsetAdjustmentBehavior contentInsetAdjustmentBehavior = scrollView.contentInsetAdjustmentBehavior;
            if (contentInsetAdjustmentBehavior != UIScrollViewContentInsetAdjustmentNever) {
                scrollView.sf_originalContentInsetAdjustmentBehavior = contentInsetAdjustmentBehavior;
                scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
                scrollView.sf_shouldRestoreContentInsetAdjustmentBehavior = YES;
            }
        }
    }
#endif
}

- (void)sf_restoreScrollViewContentInsetAdjustmentBehaviorIfNeeded {
#ifdef __IPHONE_11_0
    if (@available(iOS 11.0, *)) {
        UIScrollView *scrollView = self.sf_visibleScrollView;
        if (scrollView) {
            if (scrollView.sf_shouldRestoreContentInsetAdjustmentBehavior) {
                scrollView.contentInsetAdjustmentBehavior = scrollView.sf_originalContentInsetAdjustmentBehavior;
                scrollView.sf_shouldRestoreContentInsetAdjustmentBehavior = NO;
            }
        }
    }
#endif
}

#pragma mark - Getter & Setter

- (UINavigationBar *)sf_transitionNavigationBar {
    return objc_getAssociatedObject(self, _cmd);
}

- (void)setSf_transitionNavigationBar:(UINavigationBar *)navigationBar {
    objc_setAssociatedObject(self, @selector(sf_transitionNavigationBar), navigationBar, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (UIScrollView *)sf_scrollView {
    return sf_objc_getAssociatedWeakObject(self, _cmd);
}

- (void)setSf_scrollView:(UIScrollView *)scrollView {
    sf_objc_setAssociatedWeakObject(self, @selector(sf_scrollView), scrollView);
}

- (UIScrollView *)sf_visibleScrollView {
    UIScrollView *scrollView = self.sf_scrollView;
    if (!scrollView && [self.view isKindOfClass:[UIScrollView class]]) {
        scrollView = (UIScrollView *)self.view;
    }
    return scrollView;
}

- (BOOL)sf_navBarHidden {
    return objc_getAssociatedObject(self, _cmd);
}

- (void)setSf_navBarHidden:(BOOL)hidden {
    objc_setAssociatedObject(self, @selector(sf_navBarHidden), @(hidden), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end
